/**
 * @projectName ApexX-Cloud
 * @package com.apex.shared.redis.config
 * @className com.apex.shared.redis.config.RedisConfig
 * @copyright Copyright 2020 Thunisoft, Inc All rights reserved.
 */
package com.apex.shared.redis.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.codec.CompositeCodec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.spring.cache.CacheConfig;
import org.redisson.spring.cache.RedissonSpringCacheManager;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Redis配置类
 * 该类负责配置Redisson客户端，包括序列化、连接池、集群等配置
 * 同时也整合了Spring Cache，提供缓存管理功能
 *
 * @author MoNaiHui
 */
@AutoConfiguration
@EnableCaching
public class RedisConfig implements CachingConfigurer {

    @Resource
    private RedissonProperties redissonProperties;

    @Resource
    private ObjectMapper jacksonObjectMapper;

    /**
     * 配置 RedissonClient Bean
     * 该方法负责创建和配置Redisson客户端实例，包括：
     * 1. 使用全局ObjectMapper进行序列化
     * 2. 配置复合编解码器，支持字符串和JSON格式
     * 3. 配置线程池
     * 4. 根据配置选择单机或集群模式
     *
     * @return RedissonClient 配置完成的Redisson客户端实例
     */
    @Bean
    public RedissonClient redissonCustomizer() {
        // 创建Redisson配置对象
        Config config = new Config();
        // 配置复合编解码器：字符串编解码器用于键，JSON编解码器用于值
        config.setCodec(new CompositeCodec(new StringCodec(), new JsonJacksonCodec(jacksonObjectMapper),
                new JsonJacksonCodec(jacksonObjectMapper)));
        // 配置线程池
        config.setThreads(redissonProperties.getThreads())
                .setNettyThreads(redissonProperties.getNettyThreads());

        // 配置单机模式
        RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
        if (singleServerConfig != null) {
            config.useSingleServer()
                    // 设置Redis服务器地址
                    .setAddress(singleServerConfig.getAddress())
                    // 设置密码
                    .setPassword(singleServerConfig.getPassword())
                    // 设置数据库
                    .setDatabase(singleServerConfig.getDatabase())
                    // 设置客户端名称
                    .setClientName(singleServerConfig.getClientName())
                    // 最小空闲连接数
                    .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
                     // 连接池大小
                    .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize())
                    // 空闲连接超时
                    .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
                    // 命令超时
                    .setTimeout(singleServerConfig.getTimeout())
                    // 重试次数
                    .setRetryAttempts(singleServerConfig.getRetryAttempts())
                    // 重试间隔
                    .setRetryInterval(singleServerConfig.getRetryInterval());
        }

        // 配置集群模式
        RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();
        if (clusterServersConfig != null) {
            config.useClusterServers()
                    // 命令超时
                    .setTimeout(clusterServersConfig.getTimeout())
                    // 客户端名称
                    .setClientName(clusterServersConfig.getClientName())
                    // 空闲连接超时
                    .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
                    // 订阅连接池大小
                    .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
                    // 主节点最小空闲连接数
                    .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
                    // 主节点连接池大小
                    .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
                    // 从节点最小空闲连接数
                    .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
                    // 从节点连接池大小
                    .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
                    // 读取模式
                    .setReadMode(clusterServersConfig.getReadMode())
                    // 订阅模式
                    .setSubscriptionMode(clusterServersConfig.getSubscriptionMode())
                    // 重试次数
                    .setRetryAttempts(clusterServersConfig.getRetryAttempts())
                    // 重试间隔
                    .setRetryInterval(clusterServersConfig.getRetryInterval());
        }

        return Redisson.create(config);
    }

    /**
     * 配置Spring Cache管理器
     * 整合Redisson的分布式缓存功能到Spring Cache框架
     *
     * @param redissonClient Redisson客户端实例
     * @return CacheManager Spring Cache管理器实例
     */
    @Bean
    public CacheManager cacheManager(RedissonClient redissonClient) {
        List<RedissonProperties.CacheGroup> cacheGroup = redissonProperties.getCacheGroup();
        Map<String, CacheConfig> config = new HashMap<>();
        // 配置每个缓存组的参数
        for (RedissonProperties.CacheGroup group : cacheGroup) {
            CacheConfig cacheConfig = new CacheConfig(group.getTtl(), group.getMaxIdleTime());
            cacheConfig.setMaxSize(group.getMaxSize());
            config.put(group.getGroupId(), cacheConfig);
        }
        return new RedissonSpringCacheManager(redissonClient, config);
    }
}
